﻿using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace Marmat.Common.Http
{

    internal class HttpCommandFactoryInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            // 初始化变量
            MethodInfo method = invocation.Method;
            Type proxyType = invocation.Proxy.GetType();

            //// 获取所有的aop特性，并遍历执行，如果遇到cancel 等于true时。则直接退出
            //IEnumerable<CommandInvocationAttribute> aopCollection = method.GetCustomAttributes<CommandInvocationAttribute>();
            //object returnValue = default;
            //foreach (var item in aopCollection)
            //{
            //    MethodExecutionArgs arg = new MethodExecutionArgs(invocation.InvocationTarget, method, invocation.Arguments);
            //    item.OnEntry(arg);
            //    returnValue = arg.ReturnValue;
            //    if (arg.Cancel)
            //    {
            //        invocation.ReturnValue = returnValue;
            //        return;
            //    }
            //}

            string host = string.Empty;
            var httpHost = proxyType.GetCustomAttribute<HttpHost>();
            if (httpHost != null)
                host = httpHost.Host;

            // 根据方法的属性和方法的特性，生成对应的model和action信息。
            

            string model = method.DeclaringType.Name;
            string action = method.Name;
            ModelAttribute modelAttribute = invocation.Proxy.GetType().GetCustomAttribute<ModelAttribute>();
            ActionAttribute actionAttribute = method.GetCustomAttribute<ActionAttribute>();
            UseConnectionAttribute instanceConnection = invocation.Proxy.GetType().GetCustomAttribute<UseConnectionAttribute>();
            UseConnectionAttribute methodConnection = method.GetCustomAttribute<UseConnectionAttribute>();
            IgnoreParameterNameAttribute ignore = method.GetCustomAttribute<IgnoreParameterNameAttribute>();

            if (modelAttribute != null) model = modelAttribute.Name;
            if (actionAttribute != null) action = actionAttribute.Name;
            // 根据方法的参数和传入的属性，转换成可序列化的参数，便于提交给服务端。
            ParameterInfo[] parameters = method.GetParameters();
            Newtonsoft.Json.Linq.JToken data = null;
            if (ignore != null)
            {
                if (invocation.Arguments.Length == 1)
                {
                    object value = invocation.Arguments[0];
                    if (value is null && parameters[0].IsOptional)
                        value = parameters[0].DefaultValue;
                    if (value != null)
                        data = Newtonsoft.Json.Linq.JToken.FromObject(value);
                }
                else
                {
                    throw new Exception($"{nameof(IgnoreParameterNameAttribute)}  声明的方法只能接收一个参数。");
                }
            }
            else if (invocation.Arguments.Length > 0)
            {
                Newtonsoft.Json.Linq.JObject body = new Newtonsoft.Json.Linq.JObject();
                foreach (var parameter in parameters)
                {
                    object value = null;
                    if (invocation.Arguments.Length > parameter.Position)
                        value = invocation.Arguments[parameter.Position];
                    else if (parameter.IsOptional)
                        value = parameter.DefaultValue;
                    if (value != null)
                        body[parameter.Name] = Newtonsoft.Json.Linq.JToken.FromObject(value);
                    else
                        body[parameter.Name] = null;
                }
                data = body;
            }
            // 获取 IConnection 接口实例。
            IConnection connection;
            if (methodConnection != null)
                connection = methodConnection.Type.Assembly.CreateInstance(methodConnection.Type.FullName) as IConnection;
            else if (instanceConnection != null)
                connection = instanceConnection.Type.Assembly.CreateInstance(instanceConnection.Type.FullName) as IConnection;
            else
                connection = this.GetService<IConnection>();

            // 通过 IConnection 接口，将请求转发出去并拿到结果。
            object resultValue = connection.ExecuteCommand(model, action, data);

            // 获取所有的aop特性，并遍历执行，如果遇到cancel 等于true时。则直接退出
            if (resultValue != null)
                resultValue = this.DeserializeResultValue(resultValue, invocation.Method.ReturnType);

            foreach (var item in aopCollection)
            {
                MethodExecutionArgs arg = new MethodExecutionArgs(invocation.InvocationTarget, invocation.Method, invocation.Arguments, resultValue);
                item.OnExit(arg);
                resultValue = arg.ReturnValue;
                if (arg.Cancel)
                    break;
            }
            invocation.ReturnValue = resultValue;
        }

        /// <summary>
        /// 将得到的结果序列化成方法所声明的类型。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public virtual object DeserializeResultValue(object value, Type type)
        {
            object result;
            if (type == typeof(void))
                result = value;
            else if (type == typeof(object))
                result = value;
            else if (value is Newtonsoft.Json.Linq.JToken token)
                result = token.ToObject(type);
            else if (value is string str && string.IsNullOrEmpty(str))
                result = value;
            else
                result = Newtonsoft.Json.JsonConvert.DeserializeObject(value.ToString(), type);
            return result;
        }
    }
}
